home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 158_01 / tp.c < prev    next >
Text File  |  1987-10-10  |  7KB  |  227 lines

  1. /*    /usr/src/filters/tp.c                    */
  2. /*    =====================                    */
  3.  
  4.  
  5.  
  6. #include    <stdio.h>
  7. #include    <setjmp.h>
  8. #define        MAXLINE     640    /* #of chars in input line          */
  9. #define        LONGMAXLINE    640    /* #of chars in constructed column    */
  10. #define        MAXROW        64    /* #of non-trivial rows              */
  11. #define        SHORTLINE    64    /* #of characters in a word          */
  12. #define        SHELLBAD    1    /* UNIX shell convention for `bad'    */
  13. #define        SHELLGOOD    0    /* UNIX shell convention for `good'   */
  14. #define        FALSE        0
  15. #define        TRUE        -1
  16.  
  17.  
  18. jmp_buf    env;                /* setjmp environment        */
  19.  
  20.  
  21. main(argc, argv)
  22. int    argc;
  23. char    *argv[];
  24. {
  25.  
  26.     FILE    *fp, *tty_fp, *fopen();
  27.     int    status;            /* main's status        */
  28.  
  29.     tty_fp = fopen( "/dev/tty", "w" );
  30.  
  31.     if (argc == 1)  {        /* input from pipe        */
  32.         fprintf( tty_fp, "tp: can't work with pipe input.\n" );
  33.         return( SHELLBAD );
  34.     }
  35.     else if (argc == 2)  {        /* file on command line        */
  36.         if ( (fp = fopen(*++argv, "r") )  ==  NULL ) {
  37.             fprintf( tty_fp, "tp: can't open %s\n", *argv );
  38.             return( SHELLBAD );
  39.         }
  40.         else
  41.             ;        /* successful file open        */
  42.     }
  43.     else  {
  44.         fprintf( tty_fp, "tp: too many arguments\n" );
  45.         return( SHELLBAD );
  46.     }
  47.  
  48.  
  49.     /* Error return at the level of `do_transpose' and lower
  50.        are not implemented, i.e. "errors" are handled gracefully
  51.        and no aborts nor longjumps are used.
  52.     */
  53.  
  54.     if ( status = setjmp(env) )
  55.         ;
  56.     else
  57.         do_transpose( fp );
  58.     fclose( fp );
  59.     if ( status )  {
  60.         fprintf( tty_fp, "tp: transpose operation encounters error.\n" );
  61.         return( SHELLBAD );
  62.     }
  63.     else
  64.         return( SHELLGOOD );
  65.  
  66. }
  67.  
  68.  
  69. do_transpose( fp )
  70. FILE    *fp;                /* file-pointer: general-case    */
  71. {
  72.  
  73.     char    line[MAXLINE];        /* primary buffer        */
  74.     char    *word_pointer[MAXROW];
  75.     int    row_space, col_space;
  76.     char    mini_buffer[SHORTLINE];
  77.     char    col_buffer[LONGMAXLINE];
  78.     int    i, j;
  79.  
  80.     row_space = 0;
  81.     while ( getline(line, MAXLINE, fp) )
  82.         if ( test_nontrivial_line_length( line ) )  {
  83.             if ( row_space == 0 )
  84.                 col_space = find_column_space( line );
  85.             word_pointer[row_space++] = line;
  86.         }
  87.     for ( i = 0 ; i < col_space ; i++ )  {
  88.         rewind( fp );
  89.         *col_buffer = '\0';
  90.         for ( j = 0 ; j < row_space ; )  {
  91.             getline(line, MAXLINE, fp);
  92.             if ( test_nontrivial_line_length( line ) )  {
  93.                 read_next_col( word_pointer+j++, mini_buffer );
  94.                 append_with_gap( mini_buffer, col_buffer );
  95.             }
  96.         }
  97.         printf( "%s\n", col_buffer );
  98.     }
  99.  
  100. }
  101.  
  102.  
  103. getline(s, lim, fp)    /* get line into s[0 ---> (lim-1)], return length */
  104. char    s[];         /* generalized to use a file-pointer for the get  */
  105. int    lim;        /* During normal operation, a line is returned      */
  106. FILE    *fp;        /* and the trailing \n is also returned.      */
  107.             /* The whole line is a string, of course, and is  */
  108.             /* terminated with a \0.              */
  109.             /* s[] is guaranteed to end with a \0 even if the */
  110.             /* source character stream from the file has no   */
  111.             /* \n and is incredibly long.  In that case,      */
  112.             /* s[0] thru s[lim-2] would have source-file      */
  113.             /* characters and s[lim-1] would hold the \0.      */
  114.             /* This puts the caller's mind at ease because      */
  115.             /* he now knows that the returned "line" (which   */
  116.             /* may not actually end with \n if it is longer   */
  117.             /* that the buffer length) is always a legitimate */
  118.             /* string, i.e. it always end with \0.          */
  119. {
  120.     int    c, i;
  121.  
  122.     i = 0;
  123.     while ( --lim > 0  &&  (c=getc(fp)) != EOF  &&  c != '\n' )
  124.         s[i++] = c;
  125.     if ( c == '\n' )
  126.         s[i++] = c;
  127.     s[i] = '\0';
  128.     return(i);
  129. }
  130.  
  131.  
  132. test_nontrivial_line_length( line )    /* If line has reasonable characters, */
  133. char    *line;                /* 1 is returned, else 0 returned.    */
  134. {
  135.     for ( ; *line != '\0' ; line++ )
  136.         if ( *line != '\40' && *line != '\t' && *line != '\n' )
  137.             return( 1 );
  138.     return( 0 );
  139. }
  140.  
  141.  
  142. find_column_space( line )        /* Will find out how many words    */
  143. char    *line;                /* are on line.            */
  144. {
  145.     int    col_space;        /* measurement quantity        */
  146.     int    scanning_word;        /* useful flag            */
  147.  
  148.     for ( scanning_word = FALSE, col_space = 0 ; *line != '\0' ; line++ )
  149.         if ( *line != '\40' && *line != '\t' && *line != '\n' )  {
  150.             if ( !scanning_word )  {
  151.                 scanning_word = TRUE;
  152.                 col_space++;
  153.             }
  154.         }
  155.         else if ( scanning_word )
  156.             scanning_word = FALSE;
  157.  
  158.     return( col_space );
  159. }
  160.  
  161.  
  162. read_next_col( wpp, mini_buffer )    /* Reads the column pointed by *wpp
  163.                        into mini_buffer and try to advance
  164.                        pointer to next column.  If next
  165.                        column does not exist, leave pointer
  166.                        at current position so that next call
  167.                        will read the same (last) column.  */
  168. char    **wpp;                /* wpp :: word pointer pointer          */
  169. char    mini_buffer[];
  170. {
  171.     int    scanning_word;        /* useful flag                  */
  172.     char    *old_position;        /* last word tag in case next word
  173.                        does not exists              */
  174.     char    *p;            /* scratch pointer              */
  175.  
  176.     old_position = *wpp;
  177.     while ( (**wpp=='\40' || **wpp=='\t' || **wpp=='\n') && **wpp!='\0' )
  178.         (*wpp)++;
  179.     if (**wpp == '\0')
  180.         *wpp = old_position;
  181.     old_position = *wpp;
  182.     while ( **wpp!='\40' && **wpp!='\t' && **wpp!='\n' && **wpp!='\0' )
  183.         *mini_buffer++ = *((*wpp)++);
  184.     *mini_buffer = '\0';
  185.     while ( (**wpp=='\40' || **wpp=='\t' || **wpp=='\n') && **wpp!='\0' )
  186.         (*wpp)++;
  187.     if (**wpp == '\0')
  188.         *wpp = old_position;
  189. }
  190.  
  191.  
  192. append_with_gap( mini_buffer, col_buffer )   /* Append content of mini-buffer to
  193.                             content of col-buffer.          */
  194. char    mini_buffer[], col_buffer[];
  195. {
  196.     while (*col_buffer++ != '\0')
  197.         ;
  198.     *--col_buffer= '\40';
  199.     col_buffer++;
  200.     while (*mini_buffer != '\0')
  201.         *col_buffer++ = *mini_buffer++;
  202.     *col_buffer = '\0';
  203. }
  204.  
  205.  
  206. /******************************************************************************/
  207. /*
  208.  
  209.     This program is designed to take a file with a "matrix" of words
  210.     and output a file with the matrix transposed.
  211.     The rows are delimited by \n and the columns are delimited by
  212.     spaces.  Multiple spaces functioning as column separators
  213.     are compressed as are multiple newlines functioning as row separators.
  214.     Thus, the matrix need not look like a matrix.
  215.     In fact, the number of columns is defined by the first row.  Following
  216.     rows with excess columns have their excess discarded.  Those with
  217.     deficient columns are padded with the value of their last columns.
  218.     No parameters are required: the program will discover the number of
  219.     rows in its input by scanning the input file.
  220.     This program is intended to handle matrices of up to 64 by 64 and
  221.     where field lengths are reasonable, say 9 characters long.
  222.     Usage is defined for input file on command line.  Pipe usage
  223.     fails because of the need in the program to rewind the input stream.
  224.  
  225. */
  226. /******************************************************************************/
  227.